www.gusucode.com > VC++ 树控节点及颜色调整程序-源码程序 > VC++ 树控节点及颜色调整程序-源码程序/code/mtreectl.cpp

    // MyTreeCtrl.cpp : implementation file
// Download by http://www.NewXing.com

// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

#include "stdafx.h"
#include "CmnCtrl1.h"
#include "mtreectl.h"
#include "treecpg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMyTreeCtrl

CMyTreeCtrl::CMyTreeCtrl()
{
	m_bDragging = FALSE;
	m_pimagelist = NULL;
}

CMyTreeCtrl::~CMyTreeCtrl()
{
}


BEGIN_MESSAGE_MAP(CMyTreeCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CMyTreeCtrl)
	ON_NOTIFY_REFLECT(TVN_ENDLABELEDIT, OnEndLabelEdit)
	ON_NOTIFY_REFLECT(TVN_BEGINDRAG, OnBeginDrag)
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONUP()
	ON_WM_DESTROY()
	ON_WM_ERASEBKGND()
	ON_NOTIFY_REFLECT(TVN_BEGINRDRAG, OnBeginDrag)
	ON_WM_PAINT()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyTreeCtrl message handlers
void CMyTreeCtrl::OnDestroy()
{
	CImageList  *pimagelist;

	pimagelist = GetImageList(TVSIL_NORMAL);
	pimagelist->DeleteImageList();
	delete pimagelist;
}

void CMyTreeCtrl::SetNewStyle(long lStyleMask, BOOL bSetBits)
{
	long        lStyleOld;

	lStyleOld = GetWindowLong(m_hWnd, GWL_STYLE);
	lStyleOld &= ~lStyleMask;
	if (bSetBits)
		lStyleOld |= lStyleMask;

	SetWindowLong(m_hWnd, GWL_STYLE, lStyleOld);
	SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
}

void CMyTreeCtrl::OnEndLabelEdit(LPNMHDR pnmhdr, LRESULT *pLResult)
{
	TV_DISPINFO     *ptvinfo;

	((CTreeCtrlPage *)GetParent())->ShowNotification(pnmhdr, pLResult);
	ptvinfo = (TV_DISPINFO *)pnmhdr;
	if (ptvinfo->item.pszText != NULL)
	{
		ptvinfo->item.mask = TVIF_TEXT;
		SetItem(&ptvinfo->item);
	}
	*pLResult = TRUE;
}

void CMyTreeCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
	HTREEITEM           hitem;
	UINT                flags;

	if (m_bDragging)
	{
		ASSERT(m_pimagelist != NULL);
		m_pimagelist->DragMove(point);
		if ((hitem = HitTest(point, &flags)) != NULL)
		{
			m_pimagelist->DragLeave(this);
			SelectDropTarget(hitem);
			m_hitemDrop = hitem;
			m_pimagelist->DragEnter(this, point);
		}
	}

	CTreeCtrl::OnMouseMove(nFlags, point);
}

BOOL CMyTreeCtrl::IsChildNodeOf(HTREEITEM hitemChild, HTREEITEM hitemSuspectedParent)
{
	do
	{
		if (hitemChild == hitemSuspectedParent)
			break;
	}
	while ((hitemChild = GetParentItem(hitemChild)) != NULL);

	return (hitemChild != NULL);
}


BOOL CMyTreeCtrl::TransferItem(HTREEITEM hitemDrag, HTREEITEM hitemDrop)
{
	TV_INSERTSTRUCT     tvstruct;
	TCHAR               sztBuffer[50];
	HTREEITEM           hNewItem, hFirstChild;

		// avoid an infinite recursion situation
	tvstruct.item.hItem = hitemDrag;
	tvstruct.item.cchTextMax = 49;
	tvstruct.item.pszText = sztBuffer;
	tvstruct.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
	GetItem(&tvstruct.item);  // get information of the dragged element
	tvstruct.hParent = hitemDrop;
	tvstruct.hInsertAfter = TVI_SORT;
	tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
	hNewItem = InsertItem(&tvstruct);

	while ((hFirstChild = GetChildItem(hitemDrag)) != NULL)
	{
		TransferItem(hFirstChild, hNewItem);  // recursively transfer all the items
		DeleteItem(hFirstChild);        // delete the first child and all its children
	}
	return TRUE;
}

void CMyTreeCtrl::OnButtonUp()
{
	if (m_bDragging)
	{
		ASSERT(m_pimagelist != NULL);
		m_pimagelist->DragLeave(this);
		m_pimagelist->EndDrag();
		delete m_pimagelist;
		m_pimagelist = NULL;

		if (m_hitemDrag != m_hitemDrop && !IsChildNodeOf(m_hitemDrop, m_hitemDrag) &&
															GetParentItem(m_hitemDrag) != m_hitemDrop)
		{
			TransferItem(m_hitemDrag, m_hitemDrop);
			DeleteItem(m_hitemDrag);
		}
		else
			MessageBeep(0);

		ReleaseCapture();
		m_bDragging = FALSE;
		SelectDropTarget(NULL);
	}
}

void CMyTreeCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
	OnButtonUp();
	CTreeCtrl::OnLButtonUp(nFlags, point);
}

void CMyTreeCtrl::OnRButtonUp(UINT nFlags, CPoint point)
{
	OnButtonUp();
	CTreeCtrl::OnRButtonUp(nFlags, point);
}

void CMyTreeCtrl::OnBeginDrag(LPNMHDR pnmhdr, LRESULT *pLResult)
{
	CPoint      ptAction;
	UINT        nFlags;

	GetCursorPos(&ptAction);
	ScreenToClient(&ptAction);
	((CTreeCtrlPage *)GetParent())->ShowNotification(pnmhdr, pLResult);
	ASSERT(!m_bDragging);
	m_bDragging = TRUE;
	m_hitemDrag = HitTest(ptAction, &nFlags);
	m_hitemDrop = NULL;

	ASSERT(m_pimagelist == NULL);
	m_pimagelist = CreateDragImage(m_hitemDrag);  // get the image list for dragging
	m_pimagelist->DragShowNolock(TRUE);
	m_pimagelist->SetDragCursorImage(0, CPoint(0, 0));
	m_pimagelist->BeginDrag(0, CPoint(0,0));
	m_pimagelist->DragMove(ptAction);
	m_pimagelist->DragEnter(this, ptAction);
	SetCapture();
}

BOOL CMyTreeCtrl::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
	//return CTreeCtrl::OnEraseBkgnd(pDC);
}

/*
void CMyTreeCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	// 创建一个和显示DC相容的内存DC
	CDC memDC;
	memDC.CreateCompatibleDC( &dc );

	CRect  rcClient;
    
	//得到控件的尺寸大小
	GetClientRect(&rcClient);

	// 创建一个和显示DC配置一样的内存DC
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap( &dc, rcClient.Width(), rcClient.Height() );
	memDC.SelectObject( &bitmap );
	
	// 在内存中创建需要刷新部分的区域
	CRgn rgn;
	rgn.CreateRectRgnIndirect( &rcClient);
	memDC.SelectClipRgn(&rgn);
	rgn.DeleteObject();
	
	// 让控件作完它缺省要绘制的东西
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );


	// 创建一个MASK DC
	CDC maskDC;
	maskDC.CreateCompatibleDC(&dc);
	CBitmap maskBitmap;

	// 用CBitmap类中的成员函数CreateBitmap创建一个位图,函数原形如下
	//BOOL CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits );
    //相关参数
    //nWidth表示位图的宽度
    //nHeight表示位图的高度
    //nPlanes表示位图的色彩平面数目
    //nBitcount表示每一点显示的颜色位数,也就是说每一个点,需要用多少位来显示
    //lpBits指向一个数组,该数组包含了最初的位图位值,如果是NULL的话,新的位图就不被初始化
    //所以下面一行代码创建了一个单色的位图
	maskBitmap.CreateBitmap( rcClient.Width(), rcClient.Height(), 1, 1, NULL );
	maskDC.SelectObject( &maskBitmap ); //maskDC选择该位图
	memDC.SetBkColor( ::GetSysColor( COLOR_WINDOW ) ); //设置DC的背景颜色
    
	// 把内存DC中的内容拷贝到mask DC中去,现在maskDC中保存的位图和
	//内存DC中的位图内容是一模一样,只是颜色只有黑白两色
	maskDC.BitBlt( 0, 0, rcClient.Width(), rcClient.Height(), &memDC, 
				rcClient.left, rcClient.top, SRCCOPY );
	
	
	// 在内存DC中透明的拷贝图象
	//通过下面三行代码,memDC里面的位图的背景搞成都是黑的了,其他图标和文字保持原来的颜色
	memDC.SetBkColor(RGB(249,230,196));    
	memDC.SetTextColor(RGB(255,255,255));  
	memDC.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &maskDC, rcClient.left, rcClient.top, SRCAND);
	
	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 
					rcClient.left, rcClient.top,SRCCOPY);
}
*/


void CMyTreeCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	// 创建一个和显示DC相容的内存DC
	CDC memDC;
	memDC.CreateCompatibleDC( &dc );

	CRect  rcClient;
    
	//得到控件的尺寸大小
	GetClientRect(&rcClient);

	// 创建一个和显示DC配置一样的内存DC
	CBitmap bitmap;
	bitmap.CreateCompatibleBitmap( &dc, rcClient.Width(), rcClient.Height() );
	memDC.SelectObject( &bitmap );
	
	// 在内存中创建需要刷新部分的区域
	CRgn rgn;
	rgn.CreateRectRgnIndirect( &rcClient);
	memDC.SelectClipRgn(&rgn);
	rgn.DeleteObject();
	
	// 让控件作完它缺省要绘制的东西
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );


	// 创建一个MASK DC
	CDC maskDC;
	maskDC.CreateCompatibleDC(&dc);
	CBitmap maskBitmap;

	// 用CBitmap类中的成员函数CreateBitmap创建一个位图,函数原形如下
	//BOOL CreateBitmap( int nWidth, int nHeight, UINT nPlanes, UINT nBitcount, const void* lpBits );
    //相关参数
    //nWidth表示位图的宽度
    //nHeight表示位图的高度
    //nPlanes表示位图的色彩平面数目
    //nBitcount表示每一点显示的颜色位数,也就是说每一个点,需要用多少位来显示
    //lpBits指向一个数组,该数组包含了最初的位图位值,如果是NULL的话,新的位图就不被初始化
    //所以下面一行代码创建了一个单色的位图
	maskBitmap.CreateBitmap( rcClient.Width(), rcClient.Height(), 1, 1, NULL );
	maskDC.SelectObject( &maskBitmap ); //maskDC选择该位图
	memDC.SetBkColor( ::GetSysColor( COLOR_WINDOW ) ); //设置DC的背景颜色
    
	// 把内存DC中的内容拷贝到mask DC中去,现在maskDC中保存的位图和
	//内存DC中的位图内容是一模一样,只是颜色只有黑白两色
	maskDC.BitBlt( 0, 0, rcClient.Width(), rcClient.Height(), &memDC, 
				rcClient.left, rcClient.top, SRCCOPY );
	
	
	//dc.SetBkColor(RGB(249,230,196));
	// 在内存DC中透明的拷贝图象
	//通过下面三行代码,memDC里面的位图的背景搞成都是黑的了,其他图标和文字保持原来的颜色
	memDC.SetBkColor(RGB(0,0,0));    
	memDC.SetTextColor(RGB(255,255,255));  
	memDC.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &maskDC, rcClient.left, rcClient.top, SRCAND);
	
	//通过下面三行代码,dc里面的位图的文字背景色搞成黑色,背景保持我们指定的背景颜色
	// 用客户指定的颜色来填充控件背景
	dc.FillRect(rcClient, &CBrush(RGB(249,230,196)));
//	dc.SetBkColor(RGB(255,255,255));
	//dc.SetTextColor(RGB(0,0,0));
	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &maskDC, rcClient.left, rcClient.top, SRCAND);

	//把前景和背景相结合,完成树控件中内容的显示
	dc.BitBlt(rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), &memDC, 
					rcClient.left, rcClient.top,SRCPAINT);

}